﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using System.Web.Script.Serialization;
using Composite.Data;
using System.Transactions;
using Composite.Data.Transactions;
using LCA.Ajax;

public partial class Admin_Ajax_SystemCategoryService : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        StreamReader sr = new StreamReader(Request.InputStream);

        string str = sr.ReadToEnd();
        var table = new JavaScriptSerializer().Deserialize<dynamic>(str);

        FCResult result = ProcessData(table);
        string strResult = new JavaScriptSerializer().Serialize(result);

        Response.AddHeader("Content-Type", "text/plain");
        Response.Write(strResult);
        Response.Flush();
        Response.End();
    }

    private FCResult ProcessData(dynamic table)
    {
        string opt = table["opt"];
        FCResult result = null;
        switch (opt)
        {
            case "get_systems_by_systemcategory":
                result = GetSystemsBySystemCategory(table);
                break;
            case "update_systems_systemcategory_order":
                result = UpdateSystemOrder(table);
                break;
            case "add_system_to_systemcategory":
                result = AddSystemToSystemCategory(table);
                break;
            case "delete_system_systemcategory":
                result = DeleteSystemSystemCategory(table);
                break;
            case "create_node":
                result = CreateSystemCategory(table);
                break;
            case "rename_node":
                result = RenameSystemCategory(table);
                break;
            case "reorder_node":
                result = ReorderSystemCategory(table);
                break;
            case "delete_node":
                result = DeleteSystemCategory(table);
                break;
            case "get_nodes":
                result = GetAllSystemCatogories();
                break;
            default:
                break;
        }

        return result;
    }

    private FCResult ReorderSystemCategory(dynamic table)
    {
        // If same parent
        // Reorder for all its sibling

        // Else 
        // Reorder for all its sibling as well, under its new parent

        FCResult result = new FCResult();
        try
        {
            int position = int.Parse(table["position"].ToString());
            Guid current_node = Guid.Parse(table["current_node"]);
            Guid parent = Guid.Parse(table["parent"]);
            Guid old_parent = Guid.Parse(table["old_parent"]);
            bool isNewParent = bool.Parse(table["is_new_parent"].ToString());

            using (TransactionScope transactionScope = TransactionsFacade.CreateNewScope())
            {
                using (DataConnection conn = new DataConnection())
                {

                    // Update itself
                    LCA.Data.LCASystemCategory sc = conn.Get<LCA.Data.LCASystemCategory>().Where(x => x.Id == current_node).First();
                    sc.Parent = parent;
                    sc.Ordinal = position;

                    conn.Update<LCA.Data.LCASystemCategory>(sc);

                    // Reorder sibling on previous parent.
                    if (isNewParent)
                    {

                        List<LCA.Data.LCASystemCategory> scSiblings = (from f in conn.Get<LCA.Data.LCASystemCategory>()
                                                                  where f.Parent == old_parent && f.IsDeleted == false
                                                                  orderby f.Ordinal ascending
                                                                  select f).ToList();
                        int count = 0;
                        foreach (LCA.Data.LCASystemCategory fcat_old in scSiblings)
                        {
                            fcat_old.Ordinal = count;
                            conn.Update<LCA.Data.LCASystemCategory>(fcat_old);

                            count++;
                        }

                    }

                    // Reorder sibling on new parent, or same parent (isNewParent = false).
                    // NOT picking current_node
                    List<LCA.Data.LCASystemCategory> scSiblingsCurrent = (from f in conn.Get<LCA.Data.LCASystemCategory>()
                                                                     where f.Parent == parent && f.Id != current_node && f.IsDeleted == false
                                                                     orderby f.Ordinal ascending
                                                                     select f).ToList();
                    int count_1 = 0;
                    foreach (LCA.Data.LCASystemCategory fcat in scSiblingsCurrent)
                    {
                        if (count_1 != position)
                        {
                            fcat.Ordinal = count_1;
                            conn.Update<LCA.Data.LCASystemCategory>(fcat);
                        }
                        else
                        {
                            fcat.Ordinal = count_1 + 1;
                            conn.Update<LCA.Data.LCASystemCategory>(fcat);
                            // Additional count for current_node
                            count_1++;
                        }
                        count_1++;
                    }


                }

                transactionScope.Complete();
            }
            result.Result = true;
            result.Data = "";
        }
        catch (Exception ex)
        {
            result.Result = false;
            result.Data = ex.Message;
        }

        return result;
    }

    private FCResult DeleteSystemCategory(dynamic table)
    {
        FCResult result = new FCResult();
        try
        {
            Guid node_id = Guid.Parse(table["delete_node_id"]);


            using (TransactionScope transactionScope = TransactionsFacade.CreateNewScope())
            {
                using (DataConnection conn = new DataConnection())
                {
                    // delete current flow category
                    DeleteSystemCategory(conn, node_id);

                    // delete flowcat
                }

                transactionScope.Complete();
            }
            result.Result = true;
            result.Data = "";
        }
        catch (Exception ex)
        {
            result.Result = false;
            result.Data = ex.Message;
        }

        return result;
    }

    private void DeleteSystemCategory(DataConnection conn, Guid id)
    {
        // Delete itself
        LCA.Data.LCASystemCategory fc = (from f in conn.Get<LCA.Data.LCASystemCategory>()
                                    where f.Id == id
                                    select f).FirstOrDefault();


        fc.IsDeleted = true;
        conn.Update<LCA.Data.LCASystemCategory>(fc);

        // Delete SystemCategory - System
        var scsList = (from f in conn.Get<LCA.Data.LCASystemCategorySystem>()
                                 where f.LCASystemCategory == id
                                 select f);

        foreach (LCA.Data.LCASystemCategorySystem scs in scsList)
        {
            conn.Delete<LCA.Data.LCASystemCategorySystem>(scs);
        }



        // Do childs - Recursive
        var childs = from f in conn.Get<LCA.Data.LCASystemCategory>()
                     where f.Parent == id
                     select f;

        foreach (LCA.Data.LCASystemCategory child in childs)
        {
            DeleteSystemCategory(conn, child.Id);
        }

    }

    private FCResult RenameSystemCategory(dynamic table)
    {
        FCResult result = new FCResult();
        try
        {

            Guid flowcat_id = Guid.Parse(table["flowcat_id"]);
            string flowcat_name = table["flowcat_name"];


            using (TransactionScope transactionScope = TransactionsFacade.CreateNewScope())
            {
                using (DataConnection conn = new DataConnection())
                {
                    // Get latest ordinal of parent
                    LCA.Data.LCASystemCategory sc = conn.Get<LCA.Data.LCASystemCategory>().Where(x => x.Id == flowcat_id).First();
                    sc.Name = flowcat_name;

                    conn.Update<LCA.Data.LCASystemCategory>(sc);
                }

                transactionScope.Complete();
            }
            result.Result = true;
            result.Data = "";
        }
        catch (Exception ex)
        {
            result.Result = false;
            result.Data = ex.Message;
        }

        return result;
    }

    private FCResult CreateSystemCategory(dynamic table)
    {
        FCResult result = new FCResult();
        try
        {

            string parent_id = table["parent_id"];
            string text = table["text"];
            string previous_id = table["previous_id"];

            LCA.Data.LCASystemCategory sc = null;
            using (TransactionScope transactionScope = TransactionsFacade.CreateNewScope())
            {
                using (DataConnection conn = new DataConnection())
                {
                    // Get latest ordinal of parent
                    LCA.Data.LCASystemCategory[] lastFcs = (from f in conn.Get<LCA.Data.LCASystemCategory>()
                                                       where f.Parent == Guid.Parse(parent_id)
                                                       && f.IsDeleted == false
                                                       orderby f.Ordinal ascending
                                                       select f).ToArray();


                    int maxOrdinal = lastFcs.Length == 0 ? 0 : lastFcs.Last().Ordinal + 1;

                    sc = conn.CreateNew<LCA.Data.LCASystemCategory>();
                    sc.Name = text;
                    sc.Parent = Guid.Parse(parent_id);
                    sc.Ordinal = maxOrdinal;
                    conn.Add(sc);
                }

                transactionScope.Complete();
            }
            result.Result = true;
            result.Data = previous_id + "|" + sc.Id.ToString();
        }
        catch (Exception ex)
        {
            result.Result = false;
            result.Data = ex.Message;
        }

        return result;
    }

    private FCResult UpdateSystemOrder(dynamic table)
    {
        FCResult result = new FCResult();
        try
        {

            int rowCount = 0;

            using (TransactionScope transactionScope = TransactionsFacade.CreateNewScope())
            {
                using (DataConnection conn = new DataConnection())
                {
                    foreach (var row in table["lists"])
                    {
                        string id = row["id"].ToString();

                        LCA.Data.LCASystemCategorySystem fcf = conn.Get<LCA.Data.LCASystemCategorySystem>()
                                                .Where(x => x.Id == Guid.Parse(id)).FirstOrDefault();

                        fcf.Ordinal = rowCount;
                        conn.Update<LCA.Data.LCASystemCategorySystem>(fcf);

                        rowCount++;
                    }
                }

                transactionScope.Complete();
            }
            result.Result = true;
            result.Data = "";
        }
        catch (Exception ex)
        {
            result.Result = false;
            result.Data = ex.Message;
        }
        return result;
    }

    private FCResult DeleteSystemSystemCategory(dynamic table)
    {
        FCResult result = new FCResult();
        try
        {
            Guid fcf_id = Guid.Parse(table["fcf_id"]);


            using (TransactionScope transactionScope = TransactionsFacade.CreateNewScope())
            {
                using (DataConnection conn = new DataConnection())
                {
                    LCA.Data.LCASystemCategorySystem fcf = conn.Get<LCA.Data.LCASystemCategorySystem>().Where(x => x.Id == fcf_id).First();

                    conn.Delete(fcf);
                    
                }

                transactionScope.Complete();
            }
            result.Result = true;
            result.Data = "";
        }
        catch (Exception ex)
        {
            result.Result = false;
            result.Data = ex.Message;
        }

        return result;
    }

    private FCResult AddSystemToSystemCategory(dynamic table)
    {
        FCResult result = new FCResult();
        try
        {

            string selected_flowcat_id = table["selected_flowcat_id"];
            string system_id = table["system_id"];
            string selected_html_node_id = table["selected_html_node_id"];

            using (TransactionScope transactionScope = TransactionsFacade.CreateNewScope())
            {
                using (DataConnection conn = new DataConnection())
                {
                    // Get latest ordinal of parent
                    LCA.Data.LCASystemCategorySystem[] lastScs = (from f in conn.Get<LCA.Data.LCASystemCategorySystem>()
                                                           where f.LCASystemCategory == Guid.Parse(selected_flowcat_id)
                                                           orderby f.Ordinal ascending
                                                           select f).ToArray();

                    int maxOrdinal = lastScs.Length == 0 ? 0 : lastScs.Last().Ordinal + 1;

                    LCA.Data.LCASystemCategorySystem scs = conn.CreateNew<LCA.Data.LCASystemCategorySystem>();

                    scs.LCASystem = Guid.Parse(system_id);
                    scs.LCASystemCategory = Guid.Parse(selected_flowcat_id);
                    scs.Ordinal = maxOrdinal;

                    conn.Add(scs);
                }

                transactionScope.Complete();
            }
            result.Result = true;
            result.Data = selected_html_node_id;
        }
        catch (Exception ex)
        {
            result.Result = false;
            result.Data = ex.Message;
        }

        return result;
    }

    private FCResult GetSystemsBySystemCategory(dynamic table)
    {
        FCResult result = new FCResult();
        try
        {
            Guid systemcat_id = Guid.Parse(table["systemcat_id"]);

            dynamic systems;
            using (TransactionScope transactionScope = TransactionsFacade.CreateNewScope())
            {
                using (DataConnection conn = new DataConnection())
                {
                    // Need rowCount for rowReordering
                    systems = (from scs in conn.Get<LCA.Data.LCASystemCategorySystem>()
                             join s in conn.Get<LCA.Data.LCASystem>() on scs.LCASystem equals s.Id
                             join u in conn.Get<LCA.Data.Unit>() on s.Unit equals u.Id into joined
                             from j in joined.DefaultIfEmpty()
                             where scs.LCASystemCategory == systemcat_id
                             orderby scs.Ordinal
                             select new
                             {
                                 fID = scs.Id,
                                 Name = s.Name,
                                 fUnit = j.Name
                             }).AsEnumerable()
                            .Select((row, index) => new
                            {
                                RowCount = index + 1,
                                fID = row.fID,
                                Name = row.Name,
                                fUnit = row.fUnit == null ? "-" : row.fUnit
                            }).ToList();
                }
                transactionScope.Complete();
            }

            int count = systems.Count;

            result.Result = true;
            result.Data = new JavaScriptSerializer().Serialize(systems); ;
        }
        catch (Exception ex)
        {
            result.Result = false;
            result.Data = ex.Message;
        }

        return result;
    }

    private FCResult GetAllSystemCatogories()
    {
        FCResult result = new FCResult();
        string treeContents = "";
        try
        {
            // Retrieve the root first
            using (DataConnection conn = new DataConnection())
            {
                var roots = from sc in conn.Get<LCA.Data.LCASystemCategory>()
                            where sc.IsDeleted == false && sc.Parent == null
                            orderby sc.Ordinal
                            select sc;

                treeContents += "<ul>";

                foreach (LCA.Data.LCASystemCategory cat in roots)
                {
                    // Recursively retrieve its child
                    treeContents += string.Format("<li class='id_{2}'>{0}{1}</li>", cat.Name, GetChild(conn, cat.Id), cat.Id);
                }

                treeContents += "</ul>";

            }
            result.Result = true;
            result.Data = HttpUtility.HtmlEncode(treeContents);
        }
        catch (Exception ex)
        {
            result.Result = false;
            result.Data = ex.Message;
        }

        return result;
    }

    private string GetChild(DataConnection conn, Guid guid)
    {
        string result = "";

        var childs = from sc in conn.Get<LCA.Data.LCASystemCategory>()
                     where sc.IsDeleted == false && sc.Parent == guid
                     orderby sc.Ordinal
                     select sc;

        if (childs.Count() > 0)
        {
            result += "<ul>";

            foreach (LCA.Data.LCASystemCategory cat in childs)
            {
                result += string.Format("<li class='id_{2}'>{0}{1}</li>", cat.Name, GetChild(conn, cat.Id), cat.Id);
            }

            result += "</ul>";
        }

        return result;
    }
}

